package sym.qrcode.style;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

import sym.qrcode.encoder.ByteMatrix;
import sym.qrcode.encoder.Mosaic;
import sym.qrcode.encoder.MosaicMatrix;
import sym.qrcode.image.ImageMosaicMatrix;
import sym.qrcode.image.OutputImage;

public class GradientRoundCornerStyle extends RoundCornerStyle {
	private int slope;
	private int beginColorR;
	private int middleColorR;
	private int endColorR;
	private int beginColorG;
	private int middleColorG;
	private int endColorG;
	private int beginColorB;
	private int middleColorB;
	private int endColorB;
	private double firstaR;
	private double firstbR;
	private double secondaR;
	private double secondbR;
	private double firstaG;
	private double firstbG;
	private double secondaG;
	private double secondbG;
	private double firstaB;
	private double firstbB;
	private double secondaB;
	private double secondbB;

	public GradientRoundCornerStyle(OutputImage outputMatrix) {
		super(outputMatrix);
		// TODO Auto-generated constructor stub

	}

	public GradientRoundCornerStyle(OutputImage outputMatrix, int slope,
			Color beginColor, Color middleColor, Color endColor) {
		super(outputMatrix);
		// TODO Auto-generated constructor stub
		this.slope = slope;
		this.beginColorR = beginColor.getRed();
		this.middleColorR = middleColor.getRed();
		this.endColorR = endColor.getRed();
		this.beginColorG = beginColor.getGreen();
		this.middleColorG = middleColor.getGreen();
		this.endColorG = endColor.getGreen();
		this.beginColorB = beginColor.getBlue();
		this.middleColorB = middleColor.getBlue();
		this.endColorB = endColor.getBlue();
		calculateFunc();
	}

	private void calculateFunc() {
		// TODO Auto-generated method stub
		MosaicMatrix m = outputMatrix.getQrcode().getMosaicMatrix();
		int maxx = m.getWidth() * outputMatrix.getScale();
		int maxy = maxx;
		int max = getProjection(maxx / 2, maxy / 2);
		int max2 = getProjection(maxx, maxy);
		firstaR = (double)(middleColorR - beginColorR) / (double) max;
		firstbR = (double)beginColorR;
		secondaR = (double)(endColorR - middleColorR) / (double) (max2 - max);
		secondbR = (double)endColorR - secondaR * max2;

		firstaG = (double)(middleColorG - beginColorG) / (double) max;
		firstbG = (double)beginColorG;
		secondaG = (double)(endColorG - middleColorG) / (double) (max2 - max);
		secondbG = (double)endColorG - secondaG * max2;

		firstaB = (double)(middleColorB - beginColorB) / (double) max;
		firstbB = (double)beginColorB;
		secondaB = (double)(endColorB - middleColorB) / (double) (max2 - max);
		secondbB = (double)endColorB - secondaB * max2;
		
	}

	private int getProjection(int x, int y) {
		return x + y * slope;
	}

	private Color getColor(int x, int y) {
		int projectionLen = getProjection(x, y);
		MosaicMatrix m = outputMatrix.getQrcode().getMosaicMatrix();
		int maxx = m.getWidth() * outputMatrix.getScale();
		int maxy = maxx;
		int middle = getProjection(maxx / 2, maxy / 2);

		if (projectionLen <= middle) {
			return new Color((int) (firstaR * projectionLen + firstbR),
					(int) (firstaG * projectionLen + firstbG), (int) (firstaB
							* projectionLen + firstbB));
		} else {
			return new Color((int) (secondaR * projectionLen + secondbR),
					(int) (secondaG * projectionLen + secondbG),
					(int) (secondaB * projectionLen + secondbB));
		}
	}

	public BufferedImage getFinalImage() {
		// TODO Auto-generated method stub
		int finalWidth = outputMatrix.getMaxImageWidth() + 2 * MARGIN;
		int finalHeight = outputMatrix.getMaxImageHeight() + 2 * MARGIN;
		int scale = outputMatrix.getScale();

		BufferedImage resultImage = new BufferedImage(finalWidth, finalHeight,
				BufferedImage.TYPE_INT_RGB);
		Graphics g = resultImage.getGraphics();
		g.setColor(Color.white);
		g.fillRect(0, 0, finalWidth, finalHeight);

		MosaicMatrix m = outputMatrix.getQrcode().getMosaicMatrix();
		ByteMatrix matrix = outputMatrix.getQrcode().getMatrix();
		for (int i = 0; i < m.getWidth(); i++) {
			for (int j = 0; j < m.getHeight(); j++) {
				if (!isImage(i, j)) {
					if (matrix.get(i, j) != 0) {
						if (isLeftUp(i, j)) {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = 0; q < scale / 2; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (flag == 1) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
									} else if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.white.getRGB());
									}
								}
							}

						} else if (isLeft(i, j)) {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = 0; q < scale / 2; q++) {
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (p == 0)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
								}
							}
						} else if (isUp(i, j)) {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = 0; q < scale / 2; q++) {
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (q == 0)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
								}
							}
						} else {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = 0; q < scale / 2; q++) {
									Color color = getColor(i * scale + p, j
											* scale + q);
									resultImage.setRGB(MARGIN + i * scale + p,
											MARGIN + j * scale + q,
											color.getRGB());
								}
							}
						}

						if (isRightUp(i, j)) {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = 0; q < scale / 2; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (flag == 1) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
									} else if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.white.getRGB());
									}
								}
							}
						} else if (isRight(i, j)) {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = 0; q < scale / 2; q++) {
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (p == scale - 1)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
								}
							}
						} else if (isUp(i, j)) {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = 0; q < scale / 2; q++) {
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (q == 0)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
								}
							}
						} else {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = 0; q < scale / 2; q++) {
									Color color = getColor(i * scale + p, j
											* scale + q);
									resultImage.setRGB(MARGIN + i * scale + p,
											MARGIN + j * scale + q,
											color.getRGB());
								}
							}
						}

						if (isLeftBottom(i, j)) {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = scale / 2; q < scale; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (flag == 1) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
									} else if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.white.getRGB());
									}
								}
							}
						} else if (isLeft(i, j)) {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = scale / 2; q < scale; q++) {
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (p == 0)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
								}
							}
						} else if (isBottom(i, j)) {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = scale / 2; q < scale; q++) {
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (q == scale - 1)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
								}
							}
						} else {
							for (int p = 0; p < scale / 2; p++) {
								for (int q = scale / 2; q < scale; q++) {
									Color color = getColor(i * scale + p, j
											* scale + q);
									resultImage.setRGB(MARGIN + i * scale + p,
											MARGIN + j * scale + q,
											color.getRGB());
								}
							}
						}

						if (isRightBottom(i, j)) {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = scale / 2; q < scale; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (flag == 1) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
									} else if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.white.getRGB());
									}
								}
							}
						} else if (isRight(i, j)) {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = scale / 2; q < scale; q++) {
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (p == scale - 1)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
								}
							}
						} else if (isBottom(i, j)) {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = scale / 2; q < scale; q++) {
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (q == scale - 1)
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									else
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
								}
							}
						} else {
							for (int p = scale / 2; p < scale; p++) {
								for (int q = scale / 2; q < scale; q++) {
									Color color = getColor(i * scale + p, j
											* scale + q);
									resultImage.setRGB(MARGIN + i * scale + p,
											MARGIN + j * scale + q,
											color.getRGB());
								}
							}
						}
					}
				}
			}
		}

		for (int i = 0; i < m.getWidth(); i++) {
			for (int j = 0; j < m.getHeight(); j++) {
				if (!isImage(i, j)) {
					if (matrix.get(i, j) == 0) {
						if (isWhiteLeftUp(i, j)) {
							for (int p = -1; p < scale / 2; p++) {
								for (int q = -1; q < scale / 2; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else if (flag == 0) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
									}
								}
							}
						}
						if (isWhiteRightUp(i, j)) {
							for (int p = scale / 2; p <= scale; p++) {
								for (int q = -1; q < scale / 2; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else if (flag == 0) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
									}
								}
							}
						}
						if (isWhiteLeftBottom(i, j)) {
							for (int p = -1; p < scale / 2; p++) {
								for (int q = scale / 2; q <= scale; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else if (flag == 0) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
									}
								}
							}
						}
						if (isWhiteRightBottom(i, j)) {
							for (int p = scale / 2; p <= scale; p++) {
								for (int q = scale / 2; q <= scale; q++) {
									int flag = isInCircle(p, q, scale / 2,
											scale / 2, scale / 2);
									Color color = getColor(i * scale + p, j
											* scale + q);
									if (flag == 2) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												Color.RED.getRGB());
									} else if (flag == 0) {
										resultImage.setRGB(MARGIN + i * scale
												+ p, MARGIN + j * scale + q,
												color.getRGB());
									}
								}
							}
						}
					}
				}
			}
		}
		for (ImageMosaicMatrix m2 : outputMatrix.getMosaicList()) {
			for (int i2 = 0; i2 < m2.getWidth(); i2++)
				for (int j2 = 0; j2 < m2.getHeight(); j2++) {
					if (m2.getMatrix()[j2][i2].type == Mosaic.IMAGE) {
						for (int p = 0; p < scale; p++)
							for (int q = 0; q < scale; q++) {
								resultImage.setRGB(
										MARGIN + (m2.getX() + i2) * scale + p,
										MARGIN + (m2.getY() + j2) * scale + q,
										m2.getColorRGB(i2 * scale + p, j2
												* scale + q));
							}
					}
				}
		}
		return resultImage;
	}
}
